#include "Differentiator.h"

#include<iostream>
#include <string>

using std::string;
using std::cout; 
using std::endl;

Differentiator::Differentiator(TokenNode const* p, string const & var)
{	
	Diff(p, var);
	deleteBrackets();
}

bool Differentiator::Diff (TokenNode const* p, string const & var)
{
	switch (p->getData().getType())
	{
		case 0:
			return DiffNumber();
			break;
		case 1:
			return DiffVariable(p, var);
			break;
		case 2:
			if ((p->getData().getText()=="+") || (p->getData().getText()=="-"))
				return DiffSum(p, var);
			else if (p->getData().getText()=="*")
				return DiffMult(p, var);
			else if (p->getData().getText()=="/")
				return DiffDiv(p, var);
			break;
	}
}

bool Differentiator::DiffSum(TokenNode const* p, string const & var)
{		
	tokens_res.push_back(Token("(", Bracket));

	bool zero1=Diff (p->getLeft(), var);
	if ( (!zero1) || (zero1 && ( p->getData().getText()=="-" )) )
		tokens_res.push_back(p->getData());

	bool zero2=Diff (p->getRight(), var);	
	if ( zero2 && ((p->getData().getText()=="-") || (!zero1) ) )
	{			
			list_iterator it_end=--tokens_res.end();
			while (it_end->getText()!=p->getData().getText())
				--it_end;
			tokens_res.erase(it_end);
	}

	tokens_res.push_back(Token(")", Bracket));

	if ((zero1) && (zero2))
		return true;
	return false;	
}

bool Differentiator::DiffMult(TokenNode const* p, string const & var)
{		
	tokens_res.push_back(Token("(", Bracket));

	bool zero1=Diff (p->getLeft(), var);	
	if (!zero1)
	{
		tokens_res.push_back(p->getData());
		Push (p->getRight());
		tokens_res.push_back(Token("+", Operation));
	}

	bool zero2=Diff (p->getRight(), var);	
	if (!zero2)
	{
		tokens_res.push_back(p->getData());	
		Push (p->getLeft());
	}
	else if ((!zero1) && zero2)
	{
			list_iterator it_end=--tokens_res.end();
			while (it_end->getText()!="+")
				--it_end;
			tokens_res.erase(it_end);
	}

	tokens_res.push_back(Token(")", Bracket));

	if ((zero1) && (zero2))
		return true;	
	return false;	
}

bool Differentiator::DiffDiv(TokenNode const* p, string const & var)
{	
	tokens_res.push_back(Token("(", Bracket));

	bool zero1=Diff (p->getLeft(), var);	
	if (!zero1)
	{
		tokens_res.push_back(Token("*", Operation));
		Push (p->getRight());
	}	
	tokens_res.push_back(Token("-", Operation));
	
	bool zero2=Diff (p->getRight(), var);	
	if (!zero2)
	{
		tokens_res.push_back(Token("*", Operation));
		Push (p->getLeft());
	}
	else
	{
			list_iterator it_end=--tokens_res.end();
			while (it_end->getText()!="-")
				--it_end;
			tokens_res.erase(it_end);
	}

	tokens_res.push_back(Token(")", Bracket));

	if ((!zero1) || (!zero2))
	{		
		tokens_res.push_back(p->getData());
		tokens_res.push_back(Token("(", Bracket));
		Push (p->getRight());
		tokens_res.push_back(Token("*", Operation));
		Push (p->getRight());
		tokens_res.push_back(Token(")", Bracket));		
		return false;
	}
	else
		return true;		
}

void Differentiator::Push(TokenNode const* p)
{
	if (p->getLeft()!=0)
	{
		tokens_res.push_back(Token("(", Bracket));
		tokens_res.push_back(p->getLeft()->getData());
		tokens_res.push_back(p->getData());
		tokens_res.push_back(p->getRight()->getData());
		tokens_res.push_back(Token(")", Bracket));
	}
	else
		tokens_res.push_back(p->getData());

}

bool Differentiator::DiffNumber()
{	
	return true;
}

bool Differentiator::DiffVariable(TokenNode const* p, string const & var)
{
	if (p->getData().getText()==var)
	{
		tokens_res.push_back(Token("1", Number));		
		return false;
	}
	else		
		return true;
} 

Differentiator::const_list_iterator Differentiator::begin() const { return tokens_res.begin();  }
Differentiator::const_list_iterator Differentiator::end()   const { return (tokens_res.end());  }

void printTokensResult(const_list_iterator begin, const_list_iterator end)
{
	cout <<"TokensResult's vector"<< endl;
	if (begin==end)
		cout<<"0"<< endl;
	else
	{
		for (const_list_iterator it=begin; it!=end; ++it)
				cout << it->getText() <<" ";		
		cout <<endl;
	}
} 

void Differentiator::deleteBrackets()
{	
	list_iterator it=tokens_res.begin();	
	if (tokens_res.size() !=0 )
	{			
		list_iterator it_end=tokens_res.end();
		advance(it_end,-2);		
		if (it->getText()=="(")
		{			
			while ((it_end->getText()!="(") && (it_end->getText()!=")"))
							--it_end;
			if (it_end->getText()==")")
			{			
				++it;
				tokens_res.pop_front();
				tokens_res.pop_back();
			}
		}
	}
	if (tokens_res.size() >=2 )
	{		
		list_iterator it1=it;
		list_iterator it2=it;
		++it2;
		while (it2!=tokens_res.end())
		{
			if ( (it1->getText()=="(") && (it2->getText()==")") ) 
			{ 			
				if (it2!=--tokens_res.end())		
				{	
					++it2;			
					it1=tokens_res.erase(it1, it2);			
					if (it1!=tokens_res.begin())
						--it1;
					else
						++it2;
					it=it2;
				}
				else
				{
					tokens_res.pop_back();
					tokens_res.pop_back();
					it2=tokens_res.end();
				}
			}
			else
			{
				++it1;
				++it2;
				++it;
			}
		}
	}
		
}






